/* Includes ------------------------------------------------------------------*/
#include "stm32l_discovery_lcd.h"
#include <math.h>
#include <stdio.h>
#define BASE     (0x40020000)

#define OFF             0
#define ON              1

struct gpio {
  int mode;             //0x00
  int outputType;       
  int outputSpeed;      //0x08
  int pullUpPullDown;   
  int input;            //0x10
  int output;           
  int setReset;         //0x18
  int lock;             
  int altLow;           //0x20
  int altHigh;          
};

struct clock {
  int control;          //0x00
  int icsCalibration;   
  int config;           //0x08
  int interrupt;
  int ahbReset;         //0x10
  int apb2Reset;
  int apb1Reset;        //0x18
  int ahbEnable;       
  int apb2Enable;       //0x20
  int apb1Enable;      
  int ahbEnable_Low;    //0x28
  int apb2Enable_Low;  
  int apb1Enable_Low;   //0x30
  int controlStatus;    
};

#define GREEN_LED       0x80
#define BLUE_LED        0x40

struct gpio* portA = (struct gpio*) (BASE + 0x0000);
struct gpio* portB = (struct gpio*) (BASE + 0x0400);
struct clock* rcc  = (struct clock*)(BASE + 0x3800);

//Initializes Board


//Sets the state of the LED, takes OFF or ON.
void setGreen( int state );
void setBlue( int state );

//Private Variable
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;

/* Private function prototypes -----------------------------------------------*/
void Delay( int milliseconds );
void initLCD();
void initADC();
void sample();
void sort();
int iQaverage();
int Temperature();
uint16_t readADC1(uint8_t channel);
void init();

/*******************************************************************************/


void main()
{   
  initLCD();
  init();
  initADC();
  int array[16];
  int cond=0; 

  
  while(1){
 
    
    //Gets voltage from temperature sensor//
     
     sample(array,16);
     sort(array,16);
     int avg = iQaverage(array,16);
     int T = Temperature(avg);
    
     if(T<95){
     setBlue(1);
     setGreen(0);
     cond=0;
       
}
     if(T==95){
       cond=1;
     }
     if(cond==1){
       setBlue(1);
       setGreen(1);
    
     }
     
     if(T>=105){
       setBlue(0);
       setGreen(0);
       cond=2;
     }
 
  }
}



void initLCD(){
  /* Allow access to the RTC */
  PWR_RTCAccessCmd(ENABLE);

  /* Reset Backup Domain */
  RCC_RTCResetCmd(ENABLE);
  RCC_RTCResetCmd(DISABLE);

  /* LSE Enable */
  RCC_LSEConfig(RCC_LSE_ON);

  /* Wait till LSE is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET){}
  
  RCC_RTCCLKCmd(ENABLE);
   
  /* LCD Clock Source Selection */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
  
    /* Enable comparator clock LCD */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_LCD, ENABLE);
  
  /* Initializes the LCD glass */
  LCD_GLASS_Configure_GPIO();
  LCD_GLASS_Init();
}

void Delay( int milliseconds ) { 
  milliseconds = milliseconds * 4889;
  
  for( ;milliseconds>0;milliseconds--){}
}

void initADC() {
  /* Enable ADC clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  // Enable the internal connection of Temperature sensor and Voltage Ref 
  // with the ADC channels
  ADC_TempSensorVrefintCmd(ENABLE); 

  /* Wait until ADC+Vref+Temp sensor start */
  int adcValue = 1024;
  while (adcValue--);

  /* Setup ADC common init struct */
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  ADC_CommonInit(&ADC_CommonInitStructure);
  
  /* Enable HSI Clock */
  RCC_HSICmd(ENABLE);
  
  /*!< Wait till HSI is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET){}
  
  RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
  
  /* Initialise the ADC1 by using its init structure */
  ADC_StructInit(&ADC_InitStructure);
  // Set conversion resolution to 12bit
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;	          
  // Enable Scan mode (single conversion for each channel of the group)
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;	                          
  // Disable Continuous conversion
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;			  
  // Disable external conversion trigger
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_None; 
  // Set conversion data alignement to right
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                  
  // Set conversion data alignement to ADC_CONV_BUFF_SIZE
  ADC_InitStructure.ADC_NbrOfConversion = 1;                              
  ADC_Init(ADC1, &ADC_InitStructure); 
  
  /* Enable ADC1 */ 
  ADC_Cmd(ADC1, ENABLE); 
}

void sort(int*array, int size)
{
  for(int i = 1; i < size; i++)
  {
    int j = i-1;
    int k;
    while(array[j] > array[j+1] && j >= 0)
    {
      k = array[j+1];
      array[j+1] = array[j];
      array[j] = k;
      j = j-1;
    }
  }
}

uint16_t readADC1(uint8_t channel) { 
  ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_4Cycles); 
      
  // Start the conversion 
  ADC_SoftwareStartConv(ADC1); 
      
  // Wait until conversion completion 
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); 
      
  // Get the conversion value 
  return ADC_GetConversionValue(ADC1); 
}

void sample(int*array, int size){
  int i;
  for(i=0; i<size; i++){
    array[i] = readADC1(ADC_Channel_5);
  }
}

int iQaverage(int*array, int size){
  int start = size/4;
  int end = start*3;
  int sum;
  int count = size/2;
  for(int i=start; i<end; i++){
    sum = sum+array[i];
  }
  return sum/count;
}

int Temperature(avg){
    char str[4];
    float voltage = ((3000.0/4095.0))*avg;

    // Clears the display//
    LCD_GLASS_Clear();
  
    //Converts voltage to resistance in thermistor//
    float R = ((3000*5820)/(3000-voltage)-5820)/10000;
    
    // Simplifies following calculation//
    float temp = log(R);
    
    // Calculates Temperature per PASCO Thermistor specs //
    temp = ((1/(0.003354+(0.000256*temp)+(0.00000239*temp*temp)+(0.0000000838*temp*temp*temp))-273.15)*1.8)+32;
    
    // Converts float to int //
    int T = temp;
    
    // Creates string and displays on LCD //
    sprintf(str,"%d F",T);
    LCD_GLASS_DisplayString(str); 
    Delay(500);
    LCD_GLASS_Clear();
    
    return T;
}

void init()
{
  // Enable Port A (0x1) and Port B (0x2) Clock
  rcc->ahbEnable |= 0x1 | 0x2; 
  
  //Set Gpio Mode 7 (0x4000) and 6 (0x1000) to General Purpose Output Mode
  portB->mode |= 0x4000 | 0x1000; 
}

void setGreen(int state){
  if(state == 1){
    portB->output =  (portB->output | GREEN_LED);
    }
    else{
    portB->output = (portB->output & ~GREEN_LED);
    }
}

void setBlue(int state){
  if(state == 1){
    portB->output = (portB->output | BLUE_LED);
  }
  else{
    portB->output = (portB->output & ~BLUE_LED);
  }
}






